package grape.workflow.rest.model.mvc;

import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import grape.common.rest.form.BasePageForm;
import grape.workflow.rest.common.mvc.BaseController;
import grape.workflow.rest.model.form.DeMedalListPageForm;
import grape.workflow.rest.model.mapper.DeModelWebMapper;
import grape.workflow.rest.model.vo.DeModelVo;
import grape.workflow.service.model.api.IWorkflowDeModelService;
import grape.workflow.service.model.dto.DeModelDto;
import grape.workflow.service.model.query.DeModelQuery;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.form.api.FormDeployment;
import org.flowable.form.api.FormDeploymentBuilder;
import org.flowable.form.api.FormRepositoryService;
import org.flowable.ui.modeler.domain.AbstractModel;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.serviceapi.ModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by yangwei
 * Created at 2020/6/28 20:35
 */
@RestController
@RequestMapping("/workflow/model")
@Api(tags = "模型相关接口")
public class DeModelController extends BaseController {

    @Autowired
    private IWorkflowDeModelService iWorkflowDeModelService;
    @Autowired
    private DeModelWebMapper deModelWebMapper;
    @Autowired
    protected ModelService modelService;

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    protected FormRepositoryService formRepositoryService;

    @ApiOperation("流程模型设计分页列表")
    @PreAuthorize("hasAuthority('model:processDeModel:listPage')")
    @GetMapping(value = "/processDeModel/listPage")
    @ResponseStatus(HttpStatus.OK)
    public IPage<DeModelVo> processDeModelListPage(DeMedalListPageForm form){
        DeModelQuery param = deModelWebMapper.map(form);
        // 0为流程模型类型
        param.setModelType(AbstractModel.MODEL_TYPE_BPMN);
        return deModelListPage(form,param);
    }
    @ApiOperation("表单模型设计分页列表")
    @PreAuthorize("hasAuthority('model:formDeModel:listPage')")
    @GetMapping(value = "/formDeModel/listPage")
    @ResponseStatus(HttpStatus.OK)
    public IPage<DeModelVo> formDeModelListPage(DeMedalListPageForm form){
        DeModelQuery param = deModelWebMapper.map(form);
        // 0为流程模型类型
        param.setModelType(AbstractModel.MODEL_TYPE_FORM);
        return deModelListPage(form,param);
    }
    private IPage<DeModelVo> deModelListPage(BasePageForm form,DeModelQuery query){
        IPage page = new Page(form.getCurrent(), form.getSize());

        IPage iPage = iWorkflowDeModelService.list(page, query);
        assertPageExist(iPage);

        List<DeModelDto> list = iPage.getRecords();
        iPage.setRecords(list.stream().map(deModelWebMapper::dtoToVo).collect(Collectors.toList()));

        return iPage;
    }

    @ApiOperation("流程模型设计部署")
    @PreAuthorize("hasAuthority('model:processDeModel:deploy')")
    @PostMapping(value = "/processDeModel/deploy/{deModelId}")
    @ResponseStatus(HttpStatus.CREATED)
    public Boolean processDeModelDeploy(@PathVariable String deModelId){
        Model model = modelService.getModel(deModelId);
        BpmnModel bpmnModel = modelService.getBpmnModel(model);
        byte[] xmlBytes = modelService.getBpmnXML(bpmnModel);
        String processName = model.getName();
        // flowable ui模型中用的是.bpmn结尾 参见 org.flowable.ui.modeler.service.BaseAppDefinitionService 313 行
        if (!StringUtils.endsWith(processName, ".bpmn20.xml")){
            processName += ".bpmn20.xml";
        }
        ByteArrayInputStream in = new ByteArrayInputStream(xmlBytes);
        Deployment deployment = repositoryService.createDeployment().name(model.getName())
                .addInputStream(processName, in).deploy();
        IoUtil.close(in);
        return true;
    }

    @ApiOperation("表单模型设计部署")
    @PreAuthorize("hasAuthority('model:formDeModel:deploy')")
    @PostMapping(value = "/formDeModel/deploy/{deModelId}")
    @ResponseStatus(HttpStatus.CREATED)
    public Boolean formDeModelDeploy(@PathVariable String deModelId){
        Model model = modelService.getModel(deModelId);
        String formModelEditorJson = model.getModelEditorJson();
        byte[] formModelEditorJsonBytes = formModelEditorJson.getBytes(StandardCharsets.UTF_8);
        FormDeploymentBuilder deploymentBuilder = formRepositoryService.createDeployment();
        deploymentBuilder.tenantId(model.getTenantId());
        String processName = model.getName();
        if (!StringUtils.endsWith(model.getName(), ".form")){
            processName += ".form";
        }
        deploymentBuilder.name(model.getName());
        ByteArrayInputStream in = new ByteArrayInputStream(formModelEditorJsonBytes);
        deploymentBuilder.addInputStream(processName, in);
        FormDeployment deploy = deploymentBuilder.deploy();

        IoUtil.close(in);
        return true;
    }
}
